package pacman;

import java.awt.Point;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * Represents a time step of the pacman in the node of the Tree<T> class.
 */
public class InfoNode {

	public Info data;
	public List<InfoNode> children = new LinkedList<InfoNode>();
	
	private int totalValue;
	Direction from;
	Direction toDir;
	InfoNode toNode;
	
	public InfoNode() {
		//super();
	}

	public InfoNode(Info data) {
		this();
		setData(data);
	}

	public List<InfoNode> getChildren() {
		return this.children;
	}

	public void setChildren(List<InfoNode> children) {
		this.children = children;
	}

	public int getNumberOfChildren() {
		if (children == null) {
			return 0;
		}
		return children.size();
	}

	public void addChild(InfoNode child) {
		if (children == null) {
			children = new LinkedList<InfoNode>();
		}
		if(children.size() > 4){
			System.out.println("ERROR: Node already have 4 childern");
		}
		children.add(child);
	}

	public Info getData() {
		return this.data;
	}

	public void setData(Info data) {
		this.data = data;
	}
	
	public int getNodeValue() {
		return totalValue;
	}
	
	public boolean getDirection(GameModel m_gameModel, int[] dir){
		//int[] dir = new int [4];
		
		Point p = ((Info)data).getPoint();
		Point[] pt = new Point[4];
		for(int i=1; i<=4; i++){
			pt[i-1] = new Point(-1,-1);
			m_gameModel.m_things[0].getDestination(i, p.x, p.y, pt[i-1]);
			//System.out.println("At: ["+p.x+" "+p.y+"] => ["+pt[i-1].x+" "+pt[i-1].y+"]");
			if(pt[i-1].x == p.x && pt[i-1].y == p.y){
				//pt[i-1] = new Point(-1,-1);
				dir[i-1] = -1;
			}else{
				dir[i-1] = 1;
			}
		}
				
		return true;
	}

	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("{").append(getData().toString()).append(",[");
		int i = 0;
		for (InfoNode e : getChildren()) {
			if (i > 0) {
				sb.append(",");
			}
			sb.append(e.getData().toString());
			i++;
		}
		sb.append("]").append("}");
		return sb.toString();
	}
		
	/**
	 * Calculates the value of this node using the sum of..
	 * 1. the current node value
	 * 2. the max value of its children
	 */
	void calculateValue() {
		// calculate value for current node

		totalValue = ((Info)data).getValue();
		if (children.isEmpty()) {
			//System.out.println("node: ["+data.getPoint().x+" "+data.getPoint().y+"]"+" value: "+data.getValue()+" child: 0\n");
			return;
		}

		int maxChildValue = Integer.MIN_VALUE;
		InfoNode maxChildNode = new InfoNode();

		System.out.println("node: ["+data.getPoint().x+" "+data.getPoint().y+"]"+" curr value: "+totalValue+" max child value: "+maxChildValue);
		
		// calculate max value of children node
		for (InfoNode child : children) {
			/*
			Info childInfo = child.getData();
			if (childInfo.getValue() > maxChildValue) {
				maxChildValue = childInfo.getValue();
				maxChildNode = child;
			}
			*/
			if(child.getNodeValue() > maxChildValue) {
				maxChildValue = child.getNodeValue();
				maxChildNode = child;
			}else if(child.getNodeValue() == maxChildValue){
				if(Math.random()<=0.5){
					maxChildValue = child.getNodeValue();
					maxChildNode = child;
				}
			}
			
			System.out.println("Max: "+ maxChildValue+ " cvalue: "+ child.getNodeValue());
			
			// smarter check
			if(child.data.hasGhost){
				maxChildValue = child.getNodeValue();
				maxChildNode = child;
				System.out.println("BREAK");
				break;
			}

		}

		System.out.println("node: ["+data.getPoint().x+" "+data.getPoint().y+"]"+" curr value: "+totalValue+" max child value: "+maxChildValue+"\n");		
		totalValue += maxChildValue;
		toDir = maxChildNode.findDirectionFrom(this);
		toNode = maxChildNode;
		//System.out.println("node: ["+data.getPoint().x+" "+data.getPoint().y+"]");
	}
	
	Direction getToDirection() {
		return toDir;
	}
	
	InfoNode getToNode() {
		return toNode;
	}
	
	/**
	 * Gets a Direction enum value from the given node
	 * 
	 * [0,0] is top left
	 * 
	 * Precondition: parent is directly adjacent to this node, and is not in the same location
	 * 
	 * @param parent
	 */
	Direction findDirectionFrom(InfoNode parent) {
		Point parentLoc = parent.getData().getPoint();
		Point ourPoint = data.getPoint();
		
		if (parentLoc.y == ourPoint.y + 1) {
			return Direction.UP;
		} else if (parentLoc.y == ourPoint.y - 1) {
			return Direction.DOWN; 
		} else if (parentLoc.x == ourPoint.x + 1) {
			return Direction.LEFT;
		} else if (parentLoc.x == ourPoint.x - 1) {
			return Direction.RIGHT;
		}
		
		//something very very bad happened here (didn't follow precondition);
		//TODO: Fix to something that is sensible
		return null;
	}
	
	/**
	 * checks if the parent node is from the given direction
	 * @return
	 */
	boolean fromThisDirection(InfoNode parent, Direction dir) {
		//Direction theDir = findDirectionFrom(parent);
		return dir == findDirectionFrom(parent);
	}
}

